home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / Libraries / VideoToolbox 94.11.17 / VideoToolboxSources / WindowToEPS.c < prev    next >
Encoding:
Text File  |  1994-11-15  |  10.4 KB  |  262 lines  |  [TEXT/MPCC]

  1. /*
  2. WindowToEPS.c
  3. Copyright © 1994 Denis G. Pelli
  4.  
  5.     WindowToEPS(window,filename,rectPtr,pageRectPtr,cellsPerInch,grayLevels,reflectance);
  6.  
  7.     This is a simple but reasonably general routine to convert a grayscale
  8. image (in window or GWorld) to a PostScript file that may be transmitted to a LaserWriter or Linotype
  9. to produce a halftone image on paper. We use it a lot, and it works well.
  10.     The filename, by convention, should end in ".eps" to indicate that it is
  11. an encapsulated postscript file, but this is not enforced. The file's type is set to 'TEXT'
  12. with creator 'EPSF'. It's a plain text file.
  13.     The PixMap must have 8 bits per pixel. The window's color table is ignored. The raw
  14. pixel value (Apple calls it an "index") is transformed by the optional
  15. reflectance array (if present), and then sent directly to the printer. 
  16. If "reflectance" is NULL, then the pixel value, from 0 to 255 is
  17. interpreted by PostScript as proportional to desired reflectance, from zero to 1. 
  18. If you supply a "reflectance" array the values should range from 0.0 to 1.0.
  19. The *rectPtr indicates what
  20. part of your PixMap is to be used.
  21.     The *pageRectPtr is subtle. It describes, in typographers points
  22. (1/72"), the rectangle that your image will be mapped onto on the printed page.
  23. It is essential that you keep in mind that Apple and Adobe use different
  24. coordinate systems. Both Apple and Adobe increase x from left to right. However,
  25. Apple has y increasing from top to bottom, whereas Adobe increases y from bottom
  26. to top. Adobe's origin is the lower left corner of the page, even though that
  27. point is usually not printable, since most printers can only print to within
  28. about a half inch of the edge. The pageRect, though supplied in Apple's Rect
  29. data structure, must be in Adobe's coordinates, respecting the names of the Rect
  30. structure's fields: left, top, right, bottom. So, for an image to fill most of
  31. an 8.5x11 page, with 0.5" margins, you might use the following:
  32.  
  33.         SetRect(&pageRect,0.5*72,10.5*72,8*72,0.5*72);
  34.  
  35.     In printing PostScript halftones the halftone cell size determines both
  36. the spatial and graylevel resolutions of the resulting image. For the convenience
  37. of the user this can be specified by setting either the cellsPerInch or the
  38. grayLevels argument to the desired value; the other one should be zero. If both
  39. are zero then the printer will be left at its default cell size, which is
  40. usually a good choice. Note that there need not be any particular correspondence
  41. between pixels in your image and cells in the halftone; the printer
  42. automatically resamples your image to produce the halftone.
  43.     If you set cellsPerInch to a nonzero value then the printer will be
  44. asked to print its halftone with that many halftone cells per inch. E.g. to
  45. produce a halftone original for subsequent one-to-one reproduction in a journal,
  46. you'll want the cells to be coarse enough for them to reproduce without
  47. re-screening, e.g. 100 cells per inch.
  48.     Alternatively, if you set grayLevels to a nonzero value then the printer
  49. will be asked to print its halftone with cells containing grayLevels-1 printer
  50. pixels, yielding the specified number of gray levels. E.g. you might want to
  51. force your 300 dpi LaserWriter to use big cells yielding 256 gray levels.
  52.     Here's a minimal example:
  53.  
  54.         WindowToEPS(window,"test.eps",&rect,&pageRect,0.0,0,NULL);
  55.  
  56.     To print a screen to disk, preserving the size and scale of the image,
  57. try this:
  58.  
  59.         pageRect=window->portRect;
  60.         pageRect.top*=-1;        // convert from Apple to Adobe coordinates
  61.         pageRect.bottom*=-1;    // convert from Apple to Adobe coordinates
  62.         SetRect(&paperRect,0,11*72,8.5*72,0);
  63.         CenterRectInRect(&pageRect,&paperRect);
  64.         WindowToEPS(window,"test.eps",&window->portRect,&pageRect,0,0,NULL);
  65.  
  66.     Tiling is something we often want to do, creating a huge image by taping
  67. many pages together. Simply import your EPS file into a good graphics program,
  68. e.g. PageMaker, and print with tiling.
  69.  
  70. REFERENCES
  71.  
  72. Adobe Systems (1985) PostScript Language Reference Manual, Second Edition. 
  73. Reading, MA: Addison-Wesley.
  74.  
  75. Pelli, D. G. (1987) Programming in PostScript: Imaging on paper from a mathematical
  76. description. BYTE, 12 (5), 185-202.
  77.  
  78. HISTORY:
  79. 4/21/91    dgp    wrote it
  80. 7/24/91 dgp added comment about shifting pageRect
  81. 8/24/91    dgp    Made compatible with THINK C 5.0
  82. 12/7/91    dgp    minor editing of comments
  83. 10/10/92 dgp Added support for Pixmap's that require 32-bit addressing.
  84.             Much faster now, using table-lookup instead of sprintf for 
  85.             the hex encoding.
  86.             Deleted obsolete support for THINK C 4.
  87. 4/29/93    dgp    & jas Added explanation of how to do tiling.
  88. 5/27/93    dgp    minor editing for speed and clarity
  89. 6/15/93    dgp    Fixed silly bug introduced 5/27/93 that suppressed all hex data.
  90.             Call StripAddress.
  91. 6/29/93    dgp    Changed call interface to accept a pixmap handle instead of a pointer.
  92.             The problem with accepting a pointer is that the user must remember
  93.             to lock the handle before dereferencing it to get the pointer, and
  94.             lots of people forget, leading to a mysterious crash. Now the locking
  95.             is handled internally, automatically.
  96. 6/30/93    dgp    Added example, above, showing how to print screen to disk.
  97. 7/9/93    dgp check for 32-bit addressing capability.
  98. 12/15/93 dgp added filename argument to the diagnostic messages.
  99.             Corrected grayLevels to grayLevels-1 in computing
  100.             the required number of pixels in the halftone cell.
  101. 6/18/94    dgp    can32 is now computed by calling TrapAvailable(_SwapMMUMode), which 
  102.             returns the correct answer even on Macs with dirty ROMs.
  103. 9/5/94 dgp removed assumption in printf's that int==short.
  104. */
  105. #include "VideoToolbox.h"
  106. #include <assert.h>
  107. #include <math.h>
  108. #include <Traps.h>    // _SwapMMUMode
  109. #define CREATOR 'EPSF'    /* ?? identifies the postscript file as eps ?? */
  110.  
  111. void WindowToEPS(CWindowPtr window,char *filename,Rect *rectPtr
  112.     ,Rect *pageRectPtr,double cellsPerInch,int grayLevels,float reflectance[256])
  113. {
  114.     PixMap **pm;
  115.     FILE *file;
  116.     unsigned char *addr;
  117.     long y,bytes,width;
  118.     register long i;
  119.     unsigned short *buffer,*buffer32;
  120.     register unsigned short *word,hex[256];
  121.     register unsigned char *byte;
  122.     short pixelSize;
  123.     short rowBytes;
  124.     time_t ANSITime;
  125.     char string[100];
  126.     char mode,pmState;
  127.     static Boolean can32,is32,firstTime=1;
  128.     long gestalt;
  129.     int ok;
  130.  
  131.     assert(StackSpace()>5000);
  132.     if(firstTime){
  133.         Gestalt(gestaltAddressingModeAttr,&gestalt);
  134.         is32=gestalt&(1<<gestalt32BitAddressing);
  135.         can32=TrapAvailable(_SwapMMUMode);
  136.         firstTime=0;
  137.     }
  138.     if(IsOffScreen(window)){
  139.         // It's a GWorldPtr, lock the pixels.
  140.         ok=LockPixels(GetGWorldPixMap((GWorldPtr)window));
  141.         if(!ok)PrintfExit("%s: can't LockPixels on GWorld.\n",__FILE__);
  142.         pm=GetGWorldPixMap((GWorldPtr)window);
  143.     }else if(window->portVersion<0){    // Is it a CGrafPort or a GrafPort?
  144.         // It's a CGrafPort.
  145.         pm=window->portPixMap;
  146.     }else{
  147.         // It's a GrafPort.
  148.         PrintfExit("%s: source must be GWorld or color Window.\n",__FILE__);
  149.     }
  150.     if(cellsPerInch!=0.0 && grayLevels!=0.0)PrintfExit("%s(%s): "
  151.         "you may not specify BOTH cellsPerInch & grayLevels.\n"
  152.         "Set one to zero.\n",__FILE__,filename);
  153.     file=fopen(filename,"w");
  154.     if(file==NULL)PrintfExit("%s: Error in opening file “%s”.\n"
  155.         ,__FILE__,filename);
  156.     pmState=HGetState((Handle)pm);
  157.     HLock((Handle)pm);
  158.     addr=RectToAddress(*pm,rectPtr,&rowBytes,&pixelSize,NULL);
  159.     if(addr==NULL)PrintfExit("%s(%s): Bad PixMap.\n",__FILE__,filename);
  160.     if(pixelSize!=8)PrintfExit("%s(%s): "
  161.         "Sorry, pixelSize must be 8, not %d.\n",__FILE__,filename,(int)pixelSize);
  162.     time(&ANSITime);
  163.     strftime(string,sizeof(string),"%I:%M %p %A, %B %d, %Y",localtime(&ANSITime));
  164.     fprintf(file,
  165.         "%%!PS-Adobe-2.0 EPSF-1.2\n");
  166.     fprintf(file,
  167.         "%%%%Creator:%s\n",IdentifyApplication());
  168.     fprintf(file,
  169.         "%%%%For:%s\n",IdentifyOwner());
  170.     fprintf(file,
  171.         "%%%%Title:%s\n",filename);
  172.     fprintf(file,
  173.         "%%%%CreationDate:%s\n",string);
  174.     fprintf(file,
  175.         "%%%%Pages: 0\n"
  176.         "%%%%BoundingBox:%d %d %d %d\n"
  177.         ,(int)pageRectPtr->left,(int)pageRectPtr->bottom
  178.         ,(int)pageRectPtr->right,(int)pageRectPtr->top);
  179.     fprintf(file,
  180.         "%%%%EndComments\n"
  181.         "%%%%BeginProlog\n"
  182.         "%%%%EndProlog\n"
  183.         "%%%%BeginSetup\n"
  184.         "/VideoToolbox dup 25 dict def load begin\n"
  185.         "end\n"
  186.         "VideoToolbox begin\n"
  187.         "gsave\n"
  188.         "%%%%EndSetup\n");
  189.     fprintf(file,
  190.         "/nx %d def                %% pixels per raster line\n",(int)(rectPtr->right-rectPtr->left));
  191.     fprintf(file,
  192.         "/ny %d def                %% lines in image\n",(int)(rectPtr->bottom-rectPtr->top));
  193.     fprintf(file,
  194.         "/hypotenuse {dup mul exch dup mul add sqrt} bind def\n"
  195.         "/pixelsPerInch gsave initmatrix 72 0 dtransform hypotenuse grestore def\n"
  196.         "%d %d translate        %% locate lower left of image\n"
  197.         ,(int)pageRectPtr->left,(int)pageRectPtr->bottom);
  198.     fprintf(file,
  199.         "%d %d scale            %% print image with these dimensions on page\n"
  200.         ,(int)(pageRectPtr->right-pageRectPtr->left),(int)(pageRectPtr->top-pageRectPtr->bottom));
  201.     if(cellsPerInch!=0.0){
  202.         fprintf(file,
  203.             "/cellsPerInch %.2f def    %% halftone dot frequency\n",cellsPerInch);
  204.         fprintf(file,
  205.             "cellsPerInch currentscreen 4 -2 roll pop 3 1 roll setscreen\n");
  206.     }
  207.     if(grayLevels!=0){
  208.         fprintf(file,
  209.             "/cellsPerInch pixelsPerInch %.2f div def    %% halftone dot frequency\n"
  210.             ,sqrt(grayLevels-1));
  211.         fprintf(file,
  212.             "cellsPerInch currentscreen 4 -2 roll pop 3 1 roll setscreen\n");
  213.     }
  214.     fprintf(file,
  215.         "/s nx string def        %% string to hold one raster line\n"
  216.         "nx ny 8                    %% dimensions and bits/pixel of source image\n"
  217.         "[nx 0 0 ny neg 0 ny]    %% map unit square to PixMap data\n"
  218.         "{currentfile s readhexstring pop}    %% read data\n"
  219.         "bind                    %% speed up reading\n"
  220.         "image\n");
  221.     assert(sizeof(*byte)==1);    // required by our algorithm
  222.     assert(sizeof(*word)==2);    // required by our algorithm
  223.     if(reflectance==NULL)for(i=0;i<256;i++){
  224.         sprintf(string,"%02x",(int)i);
  225.         hex[i]=*(unsigned short *)string;
  226.     }else for(i=0;i<256;i++){
  227.         int j;
  228.         j=0.5+255*reflectance[i];
  229.         if(j<0)j=0;
  230.         if(j>255)j=255;
  231.         sprintf(string,"%02x",j);
  232.         hex[i]=*(unsigned short *)string;
  233.     }
  234.     width=rectPtr->right-rectPtr->left;
  235.     bytes=(width+1)*sizeof(*word);
  236.     buffer=(unsigned short *)NewPtr(bytes);
  237.     if(buffer==NULL)PrintfExit("%s(%s): "
  238.         "no room for %ld byte buffer.\n\007",__FILE__,filename,bytes);
  239.     buffer32=(unsigned short *)StripAddress(buffer);
  240.     for(y=rectPtr->top;y<rectPtr->bottom;y++){
  241.         mode=true32b;
  242.         if(can32)SwapMMUMode(&mode);
  243.         byte=addr;
  244.         word=buffer32;
  245.         for(i=0;i<width;i++) *word++ = hex[*byte++];
  246.         *word=0;
  247.         if(can32)SwapMMUMode(&mode);
  248.         fprintf(file,"%s\n",(char *)buffer);
  249.         addr+=rowBytes;
  250.     }
  251.     HSetState((Handle)pm,pmState);
  252.     DisposPtr((Ptr)buffer);
  253.     fprintf(file,
  254.         "%%%%Trailer\n"
  255.         "grestore\n"
  256.         "end\n"
  257.         "showpage\n"
  258.         "%%%%EOF\n");
  259.     fclose(file);
  260.     SetFileInfo(filename,'TEXT',CREATOR);
  261. }
  262.